<template>
  <div id="loadingContainer" style="padding: 50px 100px; text-align: center; min-height: calc(100vh - 72px)">
    <ElUpload
      style="padding: 30px"
      drag
      action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
      :limit="1"
      :before-upload="beforeUpload"
      multiple
      :directory="true"
    >
      <ElIcon class="el-icon--upload"><UploadFilled /></ElIcon>
      <div class="el-upload__text">Drop file here or <em>click to upload</em></div>
      <template #tip>
        <div class="el-upload__tip">jpg/png files with a size less than 500kb</div>
      </template>
    </ElUpload>
    <ElButton :disabled="isExecDisable" type="primary" icon="VideoPlay" plain @click="predictTask">预测</ElButton>
    <div>
      <ElImage
        v-if="isgotImage"
        style="width: 500px; height: 500px; margin-top: 20px"
        :src="Picurl"
        :zoom-rate="1.2"
        :max-scale="7"
        :min-scale="0.2"
        :initial-index="4"
        :preview-src-list="[Picurl]"
      />
    </div>
    <ElDescriptions v-if="isgotAccLoss" class="margin-top" title="预测准确率和损失率" :column="2" size="large" border>
      <ElDescriptionsItem>
        <template #label>
          <div class="cell-item">
            <ElIcon :style="iconStyle">
              <Tickets />
            </ElIcon>
            准确率Accuracy
          </div>
        </template>
        <ElTag size="small">{{ accuracy }}</ElTag>
      </ElDescriptionsItem>
      <ElDescriptionsItem>
        <template #label>
          <div class="cell-item">
            <ElIcon :style="iconStyle">
              <Tickets />
            </ElIcon>
            损失率Loss
          </div>
        </template>
        <ElTag size="small">{{ loss }}</ElTag>
      </ElDescriptionsItem>
    </ElDescriptions>
    <ElRow>
      <ElCol :span="12">
        <ElImage
          v-if="isgotImages"
          style="width: 100%; margin-top: 20px"
          :src="Picurl"
          :zoom-rate="1.2"
          :max-scale="7"
          :min-scale="0.2"
          :initial-index="4"
          :preview-src-list="[Picurl]"
        />
      </ElCol>
      <ElCol :span="12"
        ><div v-if="isgotBarData" ref="chartContainerRef" style="width: 100%; height: 400px"></div
      ></ElCol>
    </ElRow>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch, nextTick, computed, onBeforeUnmount } from 'vue'
import { UploadFilled } from '@element-plus/icons-vue'
import { Search } from '@element-plus/icons-vue'
import io from 'socket.io-client'
import * as echarts from 'echarts'
import { markRaw } from 'vue'
import { ElLoading } from 'element-plus'
import { useToast } from 'vuestic-ui' // 确保引入 useToast
import { useRoute } from 'vue-router'
const toast = useToast() // 创建 Toast 实例

const isExecDisable = ref(true)
let fileName = ''
const loadingInstance = ref(null)
const isgotImage = ref(false)
const isgotImages = ref(false)
const isgotAccLoss = ref(false)
const isgotBarData = ref(false)
const isFiles = ref(false)

const route = useRoute()
const modelName = ref(route.params.modelName)
console.log(modelName.value)

const type = ref('')
const Picurl = ref('')
const BarX = ref([])
const BarY = ref([])
const accuracy = ref(null)
const loss = ref(null)

const socket = io('http://localhost:5000')
let BarChart = null

const chartContainerRef = ref(null)

const iconStyle = computed(() => {
  const marginMap = {
    large: '8px',
    default: '6px',
    small: '4px',
  }
  return {
    marginRight: marginMap.large,
  }
})

watch(isgotBarData, (newVal) => {
  if (newVal) {
    // console.log('Bar')
    nextTick(() => {
      initBarChart()

      const container = chartContainerRef.value
      if (container) {
        const resizeObserver = new ResizeObserver((entries) => {
          for (const entry of entries) {
            const echartsInstance = echarts.getInstanceByDom(entry.target)
            if (echartsInstance) {
              echartsInstance.resize()
            }
          }
        })
        resizeObserver.observe(container)

        // 组件销毁时停止观察
        onBeforeUnmount(() => {
          resizeObserver.unobserve(container)
        })
      }
    })
  }
})

const initBarChart = () => {
  const chartDom = chartContainerRef.value
  if (!BarChart) {
    // 判断图表实例是否不存在
    BarChart = markRaw(echarts.init(chartDom))
  }
  // 更新图表配置
  BarChart.setOption({
    grid: {
      left: '100px', // 或者可以使用具体的像素值，例如 '50px'
      // right, top, bottom 也可以根据需要进行设置
    },
    xAxis: {
      type: 'category',
      data: BarX.value,
    },
    yAxis: {
      type: 'value',
    },
    series: [
      {
        data: BarY.value,
        type: 'bar',
      },
    ],
  })
}

const loadFileData = (filename: string) => {
  // 替换 'filename.txt' 为你的文件名
  fetch(filename)
    .then((response) => {
      if (response.ok) {
        return response.text()
      } else {
        throw new Error('Failed to fetch file')
      }
    })
    .then((data) => {
      processData(data)
    })
    .catch((error) => {
      console.error('Error fetching file:', error)
    })
}
const processData = (fileContent) => {
  const lines = fileContent.split('\n')
  const counts = {}
  lines.forEach((line) => {
    const category = line.trim()
    if (category) {
      counts[category] = (counts[category] || 0) + 1
    }
  })
  BarX.value = Object.keys(counts)
  BarY.value = Object.values(counts)
  isgotBarData.value = true
  console.log(BarX.value, BarY.value)
}

// 监听结果
const waitForAllConfirmations = () => {
  return new Promise((resolve, reject) => {
    socket.on('eval_result', (data) => {
      console.log(data)
      if (data.accuracy && data.loss) {
        // 获取图片信息
        Picurl.value = '../../../public/figures/' + type.value + '.png' // 假设data.image是图片URL
        console.log(Picurl.value)
        isgotImages.value = true

        // 获取acc和loss信息
        accuracy.value = data.accuracy
        loss.value = data.loss
        isgotAccLoss.value = true

        // 获取柱状图信息
        loadFileData('../../../public/figures/answer.txt')
      } else {
        Picurl.value = data.path // 假设data.image是图片URL
        console.log(Picurl.value)
        isgotImage.value = true
      }

      resolve(data)
    })
    setTimeout(() => {
      reject(new Error('请求超时'))
    }, 120000)
  })
}

// 定义可能的类型名称数组
const typeNames = [
  'cifar',
  'bmw',
  'PathMNIST',
  'DermaMNIST',
  'OCTMNIST',
  'PneumoniaMNIST',
  'RetinaMNIST',
  'BreastMNIST',
  'BloodMNIST',
  'TissueMNIST',
  'OrganAMNIST',
  'mnist',
]

function matchType(fileName) {
  // 将文件名转换为小写以进行不区分大小写的匹配
  const fileNameLower = fileName.toLowerCase()

  // 遍历每个类型名称以查找匹配项
  for (const typeName of typeNames) {
    // 创建一个正则表达式，不区分大小写地匹配关键字（不是完整单词）
    const regex = new RegExp(typeName.toLowerCase(), 'i')

    // 测试文件名是否包含当前类型名称
    if (regex.test(fileNameLower)) {
      return typeName // 返回原始大小写的类型名称
    }
  }

  // 如果没有找到匹配项，返回null
  return null
}

const predictTask = async () => {
  isgotImage.value = false
  isgotImages.value = false
  isgotBarData.value = false
  isgotAccLoss.value = false

  isExecDisable.value = true
  loadingInstance.value = ElLoading.service({
    target: '#loadingContainer',
    lock: true,
    // spinner: 'el-icon-loading',
    text: '预测中……',
    background: 'rgba(244, 246, 248, 0.7)',
  })
  if (isFiles.value) {
    type.value = matchType(fileName)
    console.log(type.value)
    socket.emit('model_use', {
      choice: 6,
      pchoice: 1,
      type: type.value,
      data_path: '../Data',
      subsize_rate: 0.05,
      root: 'ndb_cifar10_data/',
      global_epochs: 5,
      local_epochs: 3,
      min_available_clients: 2,
      increment: modelName.value,
      one_image_path: fileName,
      is_increment: false,
      model_save_name: 'test',
      model_name: 'resnet50',
      batch_size: 100,
      lr: 0.1,
      momentum: 0.9,
      lambda_: 0.1,
      dp: true,
      C: 1000,
      sigma: 0.01,
      q: 0.2,
      w: 2,
      value_steps: 5,
      node_id: 1,
      save_json: 'answer',
      model_save_path: './mymodel',
      k: 3,
      no_models: 3,
      address: '127.0.0.1:8080',
      feature_num: 30,
      eta: 2,
      alpha: 1.0,
      poison_label: 2,
      poisoning_per_batch: 4,
      prop: 0.6,
    })
  } else {
    socket.emit('model_use', {
      choice: 7,
      pchoice: 1,
      type: 'cifar',
      data_path: '../Data',
      subsize_rate: 0.05,
      root: 'ndb_cifar10_data/',
      global_epochs: 5,
      local_epochs: 3,
      min_available_clients: 2,
      increment: 'resnet50.pth',
      one_image_path: fileName,
      is_increment: false,
      model_save_name: 'test',
      model_name: 'resnet50',
      batch_size: 100,
      lr: 0.1,
      momentum: 0.9,
      lambda_: 0.1,
      dp: true,
      C: 1000,
      sigma: 0.01,
      q: 0.2,
      w: 2,
      value_steps: 5,
      node_id: 1,
      save_json: 'answer',
      model_save_path: './mymodel',
      k: 3,
      no_models: 3,
      address: '127.0.0.1:8080',
      feature_num: 30,
      eta: 2,
      alpha: 1.0,
      poison_label: 2,
      poisoning_per_batch: 4,
      prop: 0.6,
    })
  }

  try {
    const res = await waitForAllConfirmations()
    console.log(res)
  } catch (error) {
    console.log(error)
    toast.init({ message: error, color: 'danger' }) // 使用 Toast 实例
  }
  isExecDisable.value = false
  // isLoading.value = false
  loadingInstance.value.close()
}

const beforeUpload = (file) => {
  // console.log(file)
  if (file.type === '') {
    console.log('文件夹')
    isFiles.value = true
  } else {
    console.log('文件')
    isFiles.value = false
    // const isPTH = file.name.endsWith('.pth')
    // if (!isPTH) {
    //   this.$message.error('只能上传.pth文件！')
    //   return false
    // }
    // 用户选择了.pth文件后，直接在这里处理
  }

  fileName = file.name // 保存文件名
  isExecDisable.value = false // 设置为true
  console.log('Selected file:', fileName)
  return true
}
</script>
<style scoped>
.el-descriptions {
  margin-top: 20px;
}
.cell-item {
  display: flex;
  align-items: center;
}
.margin-top {
  margin-top: 20px;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* .spinner-icon {
  display: inline-block;
  width: 24px;
  height: 24px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #3498db;/
  border-radius: 50%;
  animation: spin 2s linear infinite;
}

.el-loading-spinner .path {
  stroke: pink;
} */
</style>
